#include <qtimer.h>
#include <qlineedit.h>
#include <qmenu.h>
#include <qmessagebox.h>
#include <qevent.h>
#include <qt_windows.h>

#include "databasedialog.h"
#include "settingsdialog.h"
#include "ui_mainwindow.h"
#include "mainwindow.h"

const QString MainWindow::INI_START_TIME = "startTime";
const QString MainWindow::INI_WORK_TIME = "workTime";
const QString MainWindow::INI_BREAK_TIME = "breakTime";
const QString MainWindow::INI_WORK_TIME_FRIDAY = "workTimeFriday";
const QString MainWindow::INI_BREAK_TIME_FRIDAY = "breakTimeFriday";
const QString MainWindow::INI_WARNING_TIME = "warningTime";
const QString MainWindow::INI_MINUS_START_TIME = "minusStartTime";
const QString MainWindow::INI_PLUS_END_TIME = "plusEndTime";

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent, Qt::MSWindowsFixedSizeDialogHint),
    ui(new Ui::MainWindow),
    m_settings("settings.ini", QSettings::IniFormat),
    m_messageShown(0),
    m_quitImmediately(false),
    m_pSysTray(__nullptr)
{
    ui->setupUi(this);
    adjustSize();

    // Datenbank
    m_pDbDlg = new DatabaseDialog(this);
    if (m_pDbDlg->hasError())
    {
        return;
    }
    m_pDbUpdateTimer = new QTimer(this);
    m_pDbUpdateTimer->setSingleShot(true);
    m_pDbUpdateTimer->setInterval(2000);
    connect(m_pDbUpdateTimer, SIGNAL(timeout()), SLOT(updateDb()));

    // Einstellungen
    m_pSettingsDlg = new SettingsDialog(this);

    // SysTray
    m_pMenuTray = new QMenu(this);
    QAction* pActionShow = m_pMenuTray->addAction("Anzeigen", this, SLOT(showWindow()));
    m_pMenuTray->addAction("Verstecken", this, SLOT(hide()));
    m_pMenuTray->addSeparator();
    m_pMenuTray->addAction("Datenbank anzeigen", this, SLOT(showDatabase()));
    m_pMenuTray->addSeparator();
    m_pMenuTray->addAction("Beenden", this, SLOT(quit()));
    m_pMenuTray->setDefaultAction(pActionShow);
    installTrayIcon();

    // Einstellungen
    m_pSettingsDlg->ui->warningTimeEdit->setTime(m_settings.value(MainWindow::INI_WARNING_TIME, QTime(0,5,0,0)).toTime());
    m_pSettingsDlg->ui->minusStartTimeEdit->setTime(m_settings.value(MainWindow::INI_MINUS_START_TIME, QTime(0,3,0,0)).toTime());
    m_pSettingsDlg->ui->plusEndTimeEdit->setTime(m_settings.value(MainWindow::INI_PLUS_END_TIME, QTime(0,2,0,0)).toTime());

    // Anfangszeit
    QDateTime startTime = QDateTime::currentDateTime();
    const QVariant& savedTime = m_settings.value(MainWindow::INI_START_TIME);

    if (savedTime.isValid() && savedTime.toDateTime().date() == startTime.date())
        startTime = savedTime.toDateTime();
    else
    {
        startTime = startTime.addMSecs(-m_pSettingsDlg->ui->minusStartTimeEdit->time().msecsSinceStartOfDay());
        m_settings.setValue(MainWindow::INI_START_TIME, startTime);
        m_settings.sync();
    }

    ui->startTimeEdit->setDateTime(startTime);

    // Arbeitszeit / Pause
    QTime breakTime, workTime;

    if (startTime.date().dayOfWeek() == Qt::Friday)
    {
        breakTime = m_settings.value(MainWindow::INI_BREAK_TIME_FRIDAY, QTime(0,15,0,0)).toTime();
        workTime = m_settings.value(MainWindow::INI_WORK_TIME_FRIDAY, QTime(6,0,0,0)).toTime();
    }
    else
    {
        breakTime = m_settings.value(MainWindow::INI_BREAK_TIME, QTime(0,30,0,0)).toTime();
        workTime = m_settings.value(MainWindow::INI_WORK_TIME, QTime(8,30,0,0)).toTime();
    }

    ui->breakTimeEdit->setTime(breakTime);
    ui->workTimeEdit->setTime(workTime);

    QTimer* pTimer = new QTimer(this);
    connect(pTimer, SIGNAL(timeout()), SLOT(showRemaining()));
    pTimer->start(50);

    // Sounds initialisieren
    m_player.setVolume(100);

    // Vorm Beenden Daten speichern
    connect(qApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
    connect(qApp, SIGNAL(aboutToQuit()), SLOT(updateTodaysEnd()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::installTrayIcon()
{
    if (m_pSysTray)
        delete m_pSysTray;

    m_pSysTray = new QSystemTrayIcon(QIcon(":/icons/clock"), this);
    m_pSysTray->setContextMenu(m_pMenuTray);
    connect(m_pSysTray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            SLOT(sysMenuAction(QSystemTrayIcon::ActivationReason)));
    m_pSysTray->setToolTip(windowTitle());
    m_pSysTray->show();
}

void MainWindow::saveSettings()
{
    m_settings.setValue(MainWindow::INI_START_TIME, ui->startTimeEdit->dateTime());

    QString breakKey, workKey;
    if (QDate::currentDate().dayOfWeek() == Qt::Friday)
    {
        breakKey = MainWindow::INI_BREAK_TIME_FRIDAY;
        workKey = MainWindow::INI_WORK_TIME_FRIDAY;
    }
    else
    {
        breakKey = MainWindow::INI_BREAK_TIME;
        workKey = MainWindow::INI_WORK_TIME;
    }

    m_settings.setValue(breakKey, ui->breakTimeEdit->time());
    m_settings.setValue(workKey, ui->workTimeEdit->time());

    m_settings.setValue(MainWindow::INI_WARNING_TIME, m_pSettingsDlg->ui->warningTimeEdit->time());
    m_settings.setValue(MainWindow::INI_MINUS_START_TIME, m_pSettingsDlg->ui->minusStartTimeEdit->time());
    m_settings.setValue(MainWindow::INI_PLUS_END_TIME, m_pSettingsDlg->ui->plusEndTimeEdit->time());

    m_settings.sync();
}

void MainWindow::showDatabase()
{
    m_pDbDlg->showNormal();
    m_pDbDlg->activateWindow();
    m_pDbDlg->raise();
}

void MainWindow::showSettings()
{
    m_pSettingsDlg->showNormal();
    m_pSettingsDlg->activateWindow();
    m_pSettingsDlg->raise();
}

void MainWindow::updateDb()
{
    saveSettings();
    m_pDbDlg->updateToday(ui->startTimeEdit->time(),
                          ui->breakTimeEdit->time());
}

void MainWindow::updateTodaysEnd()
{
    m_pDbDlg->updateTodaysEnd(m_pSettingsDlg->ui->plusEndTimeEdit->time().msecsSinceStartOfDay());
}

void MainWindow::recalculate()
{
    const qint64 msecs = ui->startTimeEdit->dateTime().toMSecsSinceEpoch() +
            ui->breakTimeEdit->time().msecsSinceStartOfDay() +
            ui->workTimeEdit->time().msecsSinceStartOfDay();

    ui->endTimeEdit->setDateTime(QDateTime::fromMSecsSinceEpoch(msecs));

    m_pDbUpdateTimer->start();
}

void MainWindow::showRemaining()
{
    const qint64 msecs = QDateTime::currentDateTime().msecsTo(ui->endTimeEdit->dateTime());
    const QTime remaining(QTime::fromMSecsSinceStartOfDay(msecs));
    ui->remainingTimeEdit->setTime(remaining);
    m_pSysTray->setToolTip(QString("%1\n%2 verbleibend").
                           arg(windowTitle()).
                           arg(remaining.toString("HH:mm:ss")));

    if (msecs <= 0)
    {
        if (m_messageShown < 2)
        {
            m_messageShown = 2;
            m_pSysTray->showMessage("Zeit zum hoam geh!",
                                  QString("scha %1 Stunden").arg(ui->workTimeEdit->time().toString("HH:mm")),
                                  QSystemTrayIcon::Critical);
            ui->remainingTimeEdit->setTime(QTime(0,0,0,0));
            m_player.setMedia(QUrl::fromLocalFile("Resources/alert.wav"));
            m_player.play();
        }
    }
    else if (msecs < m_pSettingsDlg->ui->warningTimeEdit->time().msecsSinceStartOfDay())
    {
        if (m_messageShown < 1)
        {
            m_messageShown = 1;
            m_pSysTray->showMessage(
                        "Boid is Zeit zum hoam geh!",
                        QString("in %1 Minuten").arg(m_pSettingsDlg->ui->warningTimeEdit->time().msecsSinceStartOfDay() / 60000),
                        QSystemTrayIcon::Warning);

            QString soundFile = "Resources/warning.wav";
            if (ui->startTimeEdit->date().dayOfWeek() == Qt::Friday)
                soundFile = "Resources/warning_friday.wav";

            m_player.setMedia(QUrl::fromLocalFile(soundFile));
            m_player.play();
        }
    }
    else
        m_messageShown = 0;
}

void MainWindow::sysMenuAction(QSystemTrayIcon::ActivationReason i_reason)
{
    if (i_reason == QSystemTrayIcon::Trigger)
    {
       showWindow();
    }
}

void MainWindow::changeEvent(QEvent* e)
{
    if (e->type() == QEvent::WindowStateChange && isMinimized())
    {
        hide();
    }
    else
        QMainWindow::changeEvent(e);
}

void MainWindow::closeEvent(QCloseEvent* e)
{
    if (!m_quitImmediately)
    {
        if (QMessageBox::question(this, QString(), windowTitle() + " beenden?") == QMessageBox::Yes)
            QMainWindow::closeEvent(e);
        else
            e->ignore();
    }
    else
        QMainWindow::closeEvent(e);

    if (e->isAccepted())
    {
        if (!m_pDbDlg->hasError())
        {
            saveSettings();
            updateTodaysEnd();
        }
        PostQuitMessage(0);
    }
}

void MainWindow::showWindow()
{
    showNormal();
    activateWindow();
    raise();

    installTrayIcon();
}

void MainWindow::quit()
{
    m_quitImmediately = true;
    close();
}
